﻿#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>


//EOF
//它是end of file的缩写，表示"文字流"（stream）的结尾。
//这里的"文字流"，可以是文件（file），也可以是标准输入（stdin）。
//*可以认为每个文件的结尾处，有一个叫做EOF的特殊字符，读取到这个字符，操作系统就认为文件结束了。*
//EOF不是特殊字符，而是一个定义在头文件stdio.h的常量，一般等于-1。
//
//这样看吧：当系统读取到文件结尾，返回一个信号值EOF(也就是-1)




//对于流和标准流的理解，网上搜寻吧
//下面这个知乎上的事例很形象：
//你是个有生意头脑的人，你发现很多同学不喜欢写作业，你恰好又喜欢写作业。
//于是你弄了个业务，就是帮忙抄作业（这个业务相当于程序功能）。
//为了多赚钱，不把时间浪费在收集同学们希望你帮忙的作业上，你在你的宿舍门口放了一个箱子，
//需要你做的作业直接丢那个箱子就好了（这就算默认输入的来源，这个箱子就相当于键盘），
//你做作业的时候是按规律一本一本拿，
//做完一份再去拿一份（一份一份持续输入形成输入流，而不是做完一份就不处理下一份）。
//如果是薄薄的试卷，你喜欢用镊子夹过来处理；如果是本子，你喜欢用手抓过来处理，
//（这个方式就是对应的函数如何处理流）。

//按照如上理解，那标准流就相当于从单一到多样时，最初的单一的流
//比如最开始只有箱子(输入方式)，然后放作业(输入内容)，最后我们从箱子里用手拿(输出方式)
//这里就是相当于最初的标准流啦
 
//流可以看做一种方式(输入与输出的方式，文件打开与关闭的方式，内容放入与读取的方式等等)
//类比一条小河，丢进去一个东西，由于丢进去的方式与小河路径的不同，流向的方向与方式不同，获取东西时用手拿还是用仪器获取东西的损毁程度不同
//以上是目前的理解，以后有新的理解复习时更改




//文件初事例
//int main()
//{
//	int a = 10000;
//	FILE * pf = fopen("test.txt", "wb");//FILE*是文件指针类型
//	fwrite(&a, 4, 1, pf);//⼆进制的形式写到⽂件中
//	fclose(pf);
//	pf = NULL;
//	return 0;
//}


//fopen和fclose
//int main()
//{
//	FILE* pf = fopen("test.txt", "r");//r(只读)，为了输⼊数据，打开⼀个已经存在的⽂本⽂件(输入数据，也就是将文件中的数据输入到程序中)
//										//如果指定文件不存在，它会出错
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}
//int main()
//{
//	FILE* pf = fopen("test.txt", "w");//w(只写)，为了输出数据，打开⼀个⽂本⽂件(输出数据，也就是将数据输出到文件中)
//										//如果指定文件不存在，它会重新建立一个新的文件
//		//运行之后，如果在当前文件所在路径不存在该文件，你会发现重新创建了个文件
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}
//剩下课件里有，就不一一写就了



//文件的顺序读写

////测试fputc
//int main()
//{
//	FILE* pf = fopen("test.txt", "w");//w，只写，只能将字符等写入文件，无法将文件内容输出等
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//
//	char ch = 0;
//	for (ch = 'a'; ch <= 'z'; ch++)
//	{
//		fputc(ch, pf);//fputc，字符输⼊函数，适用于所有(包括文本文件，二进制文件等)输⼊流
//	}
//
//	//getc并不能执行，上面打开文件方式为只写
//
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}

////测试fegetc
//int main()
//{
//	FILE* pf = fopen("test.txt", "r");//r，只读，读取文件中数据，也是输入数据
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//
//	int ch = fgetc(pf);//fgetc，字符输⼊函数，适用于所有(包括文本文件，二进制文件等)输⼊流
//	printf("%c",ch);
//	ch = fgetc(pf);
//	printf("%c",ch);
//	ch = fgetc(pf);
//	printf("%c",ch);
//
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}
//int main()
//{
//	FILE* pf = fopen("test.txt", "r");//r，只读，读取文件中数据，也是输入数据
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//
//	//int ch = fgetc(pf);//fgetc，字符输⼊函数，适用于所有(包括文本文件，二进制文件等)输⼊流
//	//printf("%c",ch);
//	//ch = fgetc(pf);//提取字符是按顺序来的，具体有个光标，下面细说
//	//printf("%c",ch);
//	//ch = fgetc(pf);
//	//printf("%c",ch);
//
//	int ch = 0;
//	while ((ch = fgetc(pf)) != EOF)//这里EOF换成-1也不影响，具体EOF作用在最上面
//		printf("%c", ch);
//
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}

//测试"r+"(为了读和写打开一个文件)，fputs和fgets
//int main()
//{
//	//3步：1.打开文件 2.读写 3.关闭文件
//	 
//	//1.打开文件
//	FILE* pf = fopen("test.txt", "r+");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//
//	//2.读写
//	fputs("你好，世界！", pf);//你会发现它把原来文件存在的abcdefjhijklmnopqrstuvwxyz占据了，
//								//因为文件关闭后，我以"r+"方式打开，光标会移动到起始位置，而不是从末尾开始的
//								//下面会测试从末尾位置开始的情况(也就是"a"或者"a+"方式打开文件)
//	fputs("再见，昨天！", pf);
//	fputs("abcdef", pf);
//	rewind(pf);//这里为把光标初始化为初始位置
//	char arr[100] = { 0 };
//	while (fgets(arr, 2, pf) != NULL)//从pf所指向的文件所在光标处往后读取n(这里为2)个字符储存到arr中
//		printf("%s", arr);			//但是当n为1时，很奇怪，啥都读取不到，以后再说吧
//
//	//3.关闭文件
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}

//测试"a+"，fscanf和fprintf，sscanf和sprintf
//int fprintf( FILE* stream,   const char* format, ...);
//int sscanf ( const char * s, const char* format, ...);
//int printf (				   const char* format, ...);
//int fscanf ( FILE* stream,   const char* format, ...);
//int sprintf( char * str,	   const char* format, ...);
//int scanf  (				   const char* format, ...);
//struct S
//{
//	char name[20];
//	int age;
//}s1;
//int main()
//{
//	FILE* pf = fopen("test1.txt", "a+");//打开文件，在文件尾部追加读写，也就是说刚打开文件时，刚标在文件尾部
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//
//
//	//scanf("%s %d", s1.name, &(s1.age));//输入参数，没什么问题
//
//	fscanf(stdin, "%s %d", s1.name, &(s1.age));//用fscanf模仿scanf
//											//stdin - 标准输⼊流，在⼤多数的环境中从键盘输⼊
//	
//	//fscanf(pf,"%s %d", s1.name, &(s1.age));//这里是从pf指向的test1.txt文件中读取内容，就是从起始往后读
//										//第一个读取字符串类型数据为s1.name，第二个读取的整型数据为s1.age
//										//这个函数跟scanf类似，scanf是我们输入参数，传入地址中
//										//而这个函数是从文件中读取数据，传入地址中					
//		
//	
//
//	//fprintf(pf, "%s %d %p\n", s1.name, s1.age, &s1.age);//跟printf类似，打印类型包括很多
//	
//	printf("%s %d %p\n", s1.name, s1.age, &s1.age);//打印参数没什么问题
//
//
//	fclose(pf);
//	pf = NULL;
//
//	//fprintf(stdout, "%d", 1);//用fprintf模仿printf
//							//stdout - 标准输出流，⼤多数的环境中输出⾄显⽰器界⾯
//
//	return 0;
//}
//int main()
//{
//	char arr[] = "BeiDi is a 12 boy";//如果是BeiDi 1 is a 12 boy，下面打印结果就是BeiDi 1
//	char str[10];
//	int i;
//	sscanf(arr, "%s %d", str, &i);//从arr中读取数据放到str和i的地址当中去
//								//这个主要作用于字符串，从字符串中读取数据
//	printf("%s %d\n", str, i);
//
//	char arr1[20];
//	int a = 1;
//	sprintf(arr1, "I have %d apple", a);//将I have %d apple输入arr1，替换成(arr1,"I have 1 apple")效果一样
//								//主要作用于字符串，将数据转化为字符串并输入(打印)进指定字符串
//	printf("%s\n", arr1);
//	return 0;
//}

//测试wb+(其他的就不多测试了)，fread和fwrite
//size_t fread (	  void* ptr, size_t size, size_t count, FILE* stream);
//size_t fwrite(const void* ptr, size_t size, size_t count, FILE* stream);
//int main()
//{
//	int arr[5] = { 0,1,2,3,4 };
//	int sz = sizeof(arr) / sizeof(arr[0]);
//
//	FILE* pf = fopen("test2.txt", "wb+");//文件不存在建立一个新文件
//				//wb是为了输入(朝建立的二进制文件)数据
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//
//	fwrite(arr, sizeof(arr[0]), sz, pf);//将arr中sz个sizeof(arr[0])大小的内容输出到pf中
//										//test2.txt中数据为二进制0,1,2,3,4
//
//	rewind(pf);//重置光标为起始位置
//
//	int arr1[5] = { 0 };
//
//	fread(arr1, sizeof(arr[0]), sz, pf);//将pf中sz个sizeof(arr[0])大小的内容输入到arr1中
//
//	int i = 0;
//	for (i = 0; i < sz; i++)
//		printf("%d ", arr1[i]);
//
//	fclose(pf);
//	pf = NULL;
//	
//	return 0;
//}//fwrite和fread和wb+主要是针对二进制文件的读写




//文件的随机读写
//fseek，主要是对光标进行移动
//int fseek(FILE* stream, long int offset, int origin);
//SEEK_SET文件起始位置
//SEEK_CUR文件指针当前位置
//SEEK_END文件末尾位置
//int main()
//{
//	FILE* pf = fopen("test.txt", "r");//文件内内容初始定义为abcdef
//	if (pf == NULL)				//r，只读
//	{
//		perror("fopen");
//		return 1;
//	}
//
//	int ch = fgetc(pf);//光标一开始在起始位置，读取一次后到b前
//	printf("%c\n", ch);//a
//
//	fseek(pf, 4, SEEK_CUR);//光标从当前位置往后移动4位到f前
//	//fseek(pf, 5, SEEK_SET);//光标从起始位置往后移动4位到f前
//	//fseek(pf, -1, SEEK_END);//光标从文件末尾往前移动一位到f前
//	//上述三种运行结果是相同的
//
//	ch = fgetc(pf);
//	printf("%c\n", ch);//f
//
//	fclose(pf);
//	pf = NULL;
//	
//	return 0;
//}

//ftell，确定当前光标位置
//long int ftell ( FILE * stream );
//int main()
//{
//	FILE* pf = fopen("test.txt", "r");
//	if (pf == NULL)				
//	{
//		perror("fopen");
//		return 1;
//	}
//
//	fseek(pf, 1, SEEK_CUR);
//	printf("%d ", ftell(pf));
//	fseek(pf, 1, SEEK_CUR);
//	printf("%d ", ftell(pf));
//
//	fclose(pf);
//	pf = NULL;
//	
//	return 0;
//}

//rewind，重置光标于起始位置，上面有举例，过(\*-_-*/)




//文件读取结束的判定
//feof的使用
//int feof ( FILE * stream );
//在⽂件读取过程中，不能⽤feof函数的返回值直接来判断⽂件的是否结束(原因在下下行)。
//feof的作⽤是：当⽂件读取结束的时候，判断是读取结束的原因是否是：遇到⽂件尾结束。
//
//在这个文件开头我对于EOF进行了一定解读，但是并不是所有方式下文件读取到结尾时返回值都是EOF
//如：fgetc读取文件到结尾返回EOF，而fgets读取文件到结尾返回
//int main()
//{
//	FILE* pf = fopen("test.txt", "r");
//	if (pf == NULL)				
//	{
//		perror("fopen");
//		return 1;
//	}
//
//	//int ch = 0;
//	//while ((ch = fgetc(pf)) != EOF)
//	//{
//	//	printf("%c\n", ch);
//	//}
//	//上述明显是正常读取到结尾
//
//	char ch = 0;
//	for (ch = 'a'; ch <= 'z'; ch++)
//	{
//		fputc(ch, pf);//将ch放到pf中，但由于打开方式为r(只读)，并不能输出数据
//	}
//	//以此，虽然读取结束，明显不是到结尾了才结束的，因此下面查错才会说错误的指针
//
//	//判断是什么原因导致读取结束的
//	if (feof(pf))//用feof判断文件读取结束是否是到文件末尾，如果是feof就发挥作用了
//	{
//		printf("遇到文件末尾，读取正常结束\n");
//	}
//	else if (ferror(pf))//如果不是的话，应该是发生错误了，ferror就可以发挥作用了
//	{
//		perror("fgetc");
//	}
//
//	fclose(pf);
//	pf = NULL;
//	
//	return 0;
//}





//拷贝文件:test1.txt  ---> test2.txt
int main()
{
	FILE* pfin = fopen("test.c", "r");
	if (pfin == NULL)
	{
		perror("fopen:test.c");
		return 1;
	}
	FILE* pfout = fopen("test1.c", "w");
	if (pfout == NULL)
	{
		fclose(pfin);
		perror("fopen:test1.c");
		return  1;
	}
	int ch = 0;
	while ((ch=fgetc(pfin)) != EOF)
	{
		fputc(ch, pfout);
	}
	fclose(pfin);
	pfin = NULL;
	fclose(pfout);
	pfout = NULL;

	return 0;
}